package mrpanyu.guitool.crypt;

import java.security.SecureRandom;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.CipherMode;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.SM4;
import mrpanyu.guitool.base.annotation.Action;
import mrpanyu.guitool.base.annotation.OnParameterChange;
import mrpanyu.guitool.base.annotation.Parameter;
import mrpanyu.guitool.base.annotation.ToolModel;
import mrpanyu.guitool.base.model.ParameterType;
import mrpanyu.guitool.base.model.Tool;
import mrpanyu.guitool.base.util.CommonUtils;

@ToolModel(displayName = "国密SM4对称加密")
public class Sm4Tool {

	@Parameter(displayName = "操作", type = ParameterType.SELECT, options = { "Encrypt", "Decrypt" }, order = 1)
	private String operation = "Encrypt";

	@Parameter(displayName = "MODE", type = ParameterType.SELECT, options = { "CBC", "ECB" }, order = 2)
	private String mode = "CBC";

	@Parameter(displayName = "PADDING", type = ParameterType.SELECT, options = { "PKCS5Padding",
			"NoPadding" }, order = 3)
	private String padding = "PKCS5Padding";

	@Parameter(displayName = "密钥", description = "支持Hex或Base64格式，128bit长度", order = 4)
	private String key;

	@Parameter(displayName = "IV", description = "支持Hex或Base64格式，128bit长度", order = 5)
	private String iv;

	@Parameter(displayName = "原始内容", type = ParameterType.MULTILINE_TEXT, order = 6)
	private String content;

	@Parameter(displayName = "加密文本", type = ParameterType.MULTILINE_TEXT_LINEWRAP, description = "支持Hex或Base64格式", order = 7, visible = false)
	private String encryptedContent;

	@OnParameterChange("operation")
	public void onOperationChange(Tool tool) {
		if ("Encrypt".equals(operation)) {
			tool.getParameter("content").setVisible(true);
			tool.getParameter("encryptedContent").setVisible(false);
			tool.getAction("encrypt").setVisible(true);
			tool.getAction("decrypt").setVisible(false);
		} else {
			tool.getParameter("content").setVisible(false);
			tool.getParameter("encryptedContent").setVisible(true);
			tool.getAction("encrypt").setVisible(false);
			tool.getAction("decrypt").setVisible(true);
		}
	}

	@Action(displayName = "加密", order = 1)
	public void encrypt(Tool tool) throws Exception {
		tool.clearMessages();
		byte[] keyBytes = SecureUtil.decode(key);
		SM4 sm4 = new SM4(mode, padding, keyBytes);
		if (CommonUtils.isNotBlank(iv)) {
			byte[] ivBytes = SecureUtil.decode(iv);
			sm4.setIv(ivBytes);
		}
		sm4.setMode(CipherMode.encrypt);
		byte[] contentBytes = content.getBytes("UTF-8");
		byte[] encBytes = sm4.encrypt(contentBytes);
		String encHex = HexUtil.encodeHexStr(encBytes);
		String encBase64 = Base64.encode(encBytes);
		tool.infoMessage("加密Hex:");
		tool.infoMessage(encHex);
		tool.infoMessage("加密Base64:");
		tool.infoMessage(encBase64);

		encryptedContent = encBase64;
	}

	@Action(displayName = "解密", order = 2, visible = false)
	public void decrypt(Tool tool) throws Exception {
		tool.clearMessages();
		byte[] keyBytes = SecureUtil.decode(key);
		SM4 sm4 = new SM4(mode, padding, keyBytes);
		if (CommonUtils.isNotBlank(iv)) {
			byte[] ivBytes = SecureUtil.decode(iv);
			sm4.setIv(ivBytes);
		}
		sm4.setMode(CipherMode.decrypt);
		byte[] encBytes = SecureUtil.decode(encryptedContent);
		byte[] contentBytes = sm4.decrypt(encBytes);
		String contentText = new String(contentBytes, "UTF-8");
		tool.infoMessage("解密文本值:");
		tool.infoMessage(contentText);
	}

	@Action(displayName = "生成密钥/IV", order = 3)
	public void generateKey(Tool tool) throws Exception {
		tool.clearMessages();
		byte[] keyBytes = new SM4().getSecretKey().getEncoded();
		String keyHex = HexUtil.encodeHexStr(keyBytes);
		String keyBase64 = Base64.encode(keyBytes);
		tool.infoMessage("生成随机密钥Hex:");
		tool.infoMessage(keyHex);
		tool.infoMessage("生成随机密钥Base64:");
		tool.infoMessage(keyBase64);

		byte[] ivBytes = new byte[16];
		new SecureRandom().nextBytes(ivBytes);
		String ivHex = HexUtil.encodeHexStr(ivBytes);
		String ivBase64 = Base64.encode(ivBytes);
		tool.infoMessage("生成随机IV Hex:");
		tool.infoMessage(ivHex);
		tool.infoMessage("生成随机IV Base64:");
		tool.infoMessage(ivBase64);

		this.key = keyHex;
		this.iv = ivHex;
	}

}
